from typing import List
from smart import SmartSolver
from ui import UI, PlainUI, RichUI, TkUI

def generate_range(start: float, end: float, step: float) -> List[float]:
    return [start + i * step for i in range(int((end - start) / step) + 1)]

def run_console_ui(solver: SmartSolver, ui: UI):
    print("欢迎使用牛顿法求解器！")
    print("支持函数，例如: sin(x), cos(x), sqrt(x), log(x), exp(x), pi 等")
    while True:
        choice = ui.get_input("请选择：1. 解方程 | 2. 退出: ")
        if choice == "1":
            expr = ui.get_input("请输入方程表达式 (如 sin(x) - 1, 默认 x**2 - 2): ", "x**2 - 2")
            mode = ui.get_input("单初始值 (s) 或 区间采样 (r)? (默认 r): ", "r")
            method = ui.get_input("计算方案 (smart/original/sympy, 默认 smart): ", "smart")
            multi = ui.get_input("多进程 (smart/y/n, 默认 smart): ", "smart")
            precision = ui.get_input("精度 (仅SymPy, 默认 50): ", "50")
            digits = ui.get_input("保留小数位数 (默认 3): ", "3")
            multi_bool = True if multi == "y" else False if multi == "n" else None
            
            try:
                precision = int(precision)
                digits = int(digits)
                if mode.lower() == "s":
                    x0 = float(ui.get_input("请输入初始值 (默认 1.0): ", "1.0"))
                    roots, elapsed_time = solver.solve(expr, [x0], method, multi_bool, precision)
                else:
                    start = float(ui.get_input("请输入范围起点 (默认 -10.0): ", "-10.0"))
                    end = float(ui.get_input("请输入范围终点 (默认 10.0): ", "10.0"))
                    step = float(ui.get_input("请输入步长 (默认 1.0): ", "1.0"))
                    roots, elapsed_time = solver.solve(expr, generate_range(start, end, step), method, multi_bool, precision)
                ui.display_results(expr, roots, elapsed_time, digits)
            except Exception as e:
                print(f"错误: {str(e)}")
        elif choice == "2":
            print("退出程序")
            break
        else:
            print("无效选择，请输入1或2")

def main():
    solver = SmartSolver()
    
    ui_options = [
        (TkUI, lambda: TkUI(solver.solve), 2 if TkUI.is_available() else -1),
        (RichUI, RichUI, 1 if RichUI.is_available() else -1),
        (PlainUI, PlainUI, 0)
    ]
    ui_cls, ui_factory, _ = max(ui_options, key=lambda x: x[2])
    ui = ui_factory()

    if isinstance(ui, TkUI):
        ui.run()
    else:
        run_console_ui(solver, ui)

if __name__ == "__main__":
    main()